// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="EventQueueService.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the EventQueueService type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------

namespace ScrumForTeamSystem.EventService.Services
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;

    using ScrumForTeamSystem.EventService.Infrastructure;
    using ScrumForTeamSystem.EventService.Infrastructure.Interfaces;

    /// <summary>
    /// Defines the EventQueueService type.
    /// </summary>
    internal class EventQueueService : IEventQueueService
    {
        /// <summary>
        /// Instance of the queue
        /// </summary>
        private readonly Queue<ITfsEvent> queue;

        /// <summary>
        /// Initializes a new instance of the <see cref="EventQueueService"/> class.
        /// </summary>
        public EventQueueService()
        {
            this.queue = new Queue<ITfsEvent>();
        }

        /// <summary>
        /// Occurs when [action] event raised.
        /// </summary>
        public event EventHandler<ActionEventArgs> Message;

        /// <summary>
        /// Occurs when [exception action] event raised.
        /// </summary>
        public event EventHandler<ExceptionActionEventArgs> ExceptionMessage;

        /// <summary>
        /// Occurs when [object enqueued] event raised.
        /// </summary>
        public event EventHandler ObjectEnqueued;

        /// <summary>
        /// Gets a value indicating whether this instance has queued events.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance has queued events; otherwise, <c>false</c>.
        /// </value>
        public bool HasQueuedEvents
        {
            get
            {
                return this.queue.Count != 0;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is subscribed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is subscribed; otherwise, <c>false</c>.
        /// </value>
        private bool IsSubscribed
        {
            get
            {
                return this.Message != null && this.ExceptionMessage != null;
            }
        }

        /// <summary>
        /// Dequeues this instance.
        /// </summary>
        /// <returns>The dequed event instance</returns>
        public ITfsEvent Dequeue()
        {
            var obj = this.queue.Dequeue();

            if (this.IsSubscribed)
            {
                var actionEventArgs = new ActionEventArgs(
                        String.Format(
                                CultureInfo.CurrentUICulture,
                                "'{0}' Object Dequeued. Queue Count: {1}",
                                obj.EventSource.GetType().Name,
                                this.queue.Count));

                this.Message(this, actionEventArgs);
            }

            return obj;
        }

        /// <summary>
        /// Enqueues the specified event source.
        /// </summary>
        /// <param name="eventSource">The event source.</param>
        /// <param name="serverIdentity">The server identity.</param>
        public void Enqueue(object eventSource, TFSIdentity serverIdentity)
        {
            if (eventSource == null)
            {
                throw new ArgumentNullException("eventSource");
            }

            this.queue.Enqueue(new TfsEvent(eventSource, serverIdentity));

            if (this.IsSubscribed)
            {
                var actionEventArgs = new ActionEventArgs(
                        String.Format(
                            CultureInfo.CurrentUICulture,
                            "'{0}' Object Enqueued. Queue Count: {1}",
                            eventSource.GetType().Name,
                            this.queue.Count));

                this.Message(this, actionEventArgs);
            }

            if (this.ObjectEnqueued != null)
            {
                this.ObjectEnqueued(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Peeks the queued events.
        /// </summary>
        /// <returns>An array of events without dequing.</returns>
        public ITfsEvent[] PeekQueuedEvents()
        {
            return this.queue.ToArray();
        }

        /// <summary>
        /// Peeks the type of the queued events by event.
        /// </summary>
        /// <param name="eventType">The event type.</param>
        /// <returns>
        /// An array of events filtered by type, without dequing
        /// </returns>
        public ITfsEvent[] PeekQueuedEventsByEventType(Type eventType)
        {
            var set = from o in this.queue.ToArray() where o.EventSourceType.Equals(eventType) select o;

            return set.ToArray();
        }
    }
}